"use strict";
var q = require('q');
var models = require('./../models');
var co = require('co');
var moment = require('moment');
var EventEmitter = require('events').EventEmitter;
var Tps = require('../serialbootstrap/index').Tps;
var fs = require('fs');
var path = require('path');
var PrismSectionCalculate = require('./PrismSectionCalculate');
var AngleSectionCalculate = require('./AngleSectionCalculate');
var chalk = require('chalk');
require('console.table');
/** 全站仪的帮助控制类 */
class TpsHelper extends Tps.TPSController {
    /** 
     * 构造函数
     * @param {object} option {stationId,com}
     */
    constructor(option) {
        super(option.com);
        this.option = option;
        /** 是否可以测量,一开始默认不可以 */
        this.enabled = false;
        this.stationConfig = this.option.stationConfig; //全站仪配置
        /** 
         * 初始化全站仪控制器
         */
        this.prjId = this.option.stationConfig.prjId;
        this.prepareStation(this.option.stationConfig, []);
        this.prismList = [];
        this.distDevice = { id: 3, deviceId: 128 };//测距仪,需要用到其中的配置信息
        this.surveyFitLine = option.surveyFitLine;//测量帮助线路
        this.sectionConfigList = [];//断面配置信息
        this.angleDeviceList = [];//倾角计的设备列表
    }
    
    /** 
     * 获取数据库中已知的最大的No
     * @return {Promise} 返回int的promise
     */
    _getMaxNo() {
        var _this = this;
        return co(function* () {
            var results = yield models.sequelize.query('select max(No) as no from TargetPrismResult where StationId = ' + _this.option.stationConfig.id, { type: models.sequelize.QueryTypes.SELECT });
            if (!results[0].no) return 0;
            else return results[0].no;
        });
    }
    
    
    /** 
     * 根据该点该时刻,获取已经推进了多少里程
     */
    _getMileSum(pt) {
        var _this = this;
        return co(function* () {
            var mileSums = yield models.sequelize.query('select sum(Value) as mileSum from DistMileResult where DeviceId = ' + _this.distDevice.deviceId + ' and ConfigId = ' + _this.distDevice.id + ' and Date <= \'' + moment(pt.date).format('YYYY-MM-DD HH:mm:ss') + "'", { type: models.sequelize.QueryTypes.SELECT });
            if (mileSums[0].mileSum < 0) return 0;
            return mileSums[0].mileSum || 0;
        });
    }
    
    /** 
     * @todo
     * 开始观测,并把数据存入数据库
     */
    startSurvey() {
        try {
            if (this.isWorking) return;
            this.emit('tpssurveystart');
            this.enabled = true;
            var _this = this;
            this.firstSurveyInPipe = true;
            _this._survey();
        } catch (error) {
            console.log(error);
        }
    }
    
    /** 
     * 设置为不可观测状态,一般为换顶管时
     */
    stopSurvey() {
        this.enabled = false;
        this.emit('tpssurveystop');
    }
    
    /** 
     * 辅助测量,测量所有的点
     */
    auxiliarySurvey() {
        var _this = this;
        return co(function* () {
            yield q.delay(1000 * 5);//延迟
            console.log(chalk.green('进入辅助测量'));
            _this.prismList = yield _this.option.stationConfig.getTargetPrismConfigs();
            _this.prepareStation(_this.option.stationConfig, _this.prismList.map(prism=> { return prism.dataValues; }));
            var turnData = yield _this.survey();//全站仪测量
            if (!_this.enabled) return;
            var maxNo = yield _this._getMaxNo()
            var no = maxNo + 1;
            yield _this._surveyAuxiliaryProcress(turnData, no);
            _this.firstSurveyInPipe = false;//已经不再是第一次测量
        }).catch(function (err) {
            console.log(err.stack);
        });
    }
    
    /** 
     * 常规测量,在顶管进行时,只测pf,pb,ph
     */
    controlSurvey() {
        var _this = this;
        return co(function* () {
            if (!_this.enabled) return;
            yield q.delay(1000 * 30);
            if (!_this.enabled) return;
            console.log(chalk.green('进入常规测量'));
            _this.prismList = yield _this.option.stationConfig.getTargetPrismConfigs();
            _this.prepareStation(_this.option.stationConfig, _this.prismList.filter(function (prism) {
                return prism.type !== 'Auxiliary';
            }).map(prism=> { return prism.dataValues; }));
            var turnData = yield _this.survey();//全站仪测量
            if (!_this.enabled) return;
            var maxNo = yield _this._getMaxNo()
            var no = maxNo + 1;
            yield _this._surveyControlProcess(turnData, no);
            _this.emit('tpssurveycomplete');
            yield q.delay(500);
        }).catch(function (err) {
            console.log(err.stack);
        });
    }
    
    /** 
     * 辅助测量数据处理
     */
    _surveyAuxiliaryProcress(turnData, no) {
        var _this = this;
        return co(function* () {
            if (!_this.sectionConfigList.length) {//获取所有断面配置信息
                _this.sectionConfigList = yield models.SectionConfig.findAll({
                    where: {
                        prjId: _this.prjId
                    }
                });
            }

            var pts = turnData.surveyResultList
                .filter(function (item) {
                    return item.pass;
                })
                .map(function (pt) {
                    return Object.assign(pt, {
                        date: pt.time1,
                        no: no,
                        stationId: _this.option.stationConfig.id
                    });
                });//不pass的就不要了
            var savePts = pts.map(function (pt) {
                return {
                    name: pt.name,
                    date: pt.time1,
                    no: no,
                    e: pt.e,
                    n: pt.n,
                    h: pt.h,
                    stationId: _this.option.stationConfig.id
                }
            });
            console.table(savePts);
            yield models.TargetPrismResult.bulkCreate(savePts);//保存的到数据库
            //先进行高差校正顶管旋转
            var preDefinedPrismNames = {
                pb0: {
                    prism: ['pb', 'pb1'],//[target,prism]
                    target: true//有辅助棱镜
                },
                st0: {
                    prism: ['st', 'st1'],
                    target: true
                },
                pf0: {
                    prism: ['pf', 'pf1'],
                    target: true
                },
                ph0: {
                    prism: ['ph'],
                    target: false
                }
            };
            for (var key in preDefinedPrismNames) {
                var sectionCenter = _this.sectionConfigList.find(sect=> {
                    return sect.name === key;
                });//找到顶管配置的中心
                var targetOriginal = _this.sectionConfigList.find(sect=> {
                    return sect.name === preDefinedPrismNames[key].prism[0];
                });//找到棱镜的初始配置坐标
                var prismOriginal = null, prismNow = null;
                if (preDefinedPrismNames[key].target) {
                    prismOriginal = _this.sectionConfigList.find(sect=> {
                        return sect.name === preDefinedPrismNames[key].prism[1];
                    });//找到辅助棱镜的初始配置坐标
                    prismNow = pts.find(pt=> {
                        return pt.name === preDefinedPrismNames[key].prism[1];
                    });//找到辅助棱镜的当前坐标
                    if (prismNow) {
                        //把辅助棱镜的坐标update到数据库中
                        yield models.TargetPrismConfig.update({
                            e: prismNow.e,
                            n: prismNow.n,
                            h: prismNow.h,
                        }, {
                                where: {
                                    stationId: _this.option.stationConfig.id,
                                    name: prismNow.name
                                }
                            });
                    } else {
                        continue;
                    }
                }
                var targetNow = pts.find(pt=> {
                    return pt.name === preDefinedPrismNames[key].prism[0];
                });//找到棱镜的当前坐标
                if (preDefinedPrismNames[key].prism[0] === 'st') {
                    targetNow = _this.stationConfig.get();
                }
                if (!targetNow) continue;//没有当前棱镜姿态,什么都解算不了
                if (prismNow && sectionCenter && targetOriginal && prismOriginal) {//条件都满足了才能进行高差棱镜旋转纠正
                    var prismOption = {
                        sectionCenter: sectionCenter,
                        targetOriginal: targetOriginal,
                        prismOriginal: prismOriginal,
                        targetNow: targetNow,
                        prismNow: prismNow
                    };

                    var coorDiff = yield models.CoorDiff.findOne({
                        where: {
                            prjId: _this.prjId,
                            name: targetNow.name
                        }
                    });
                    var prismSectionCaculate = new PrismSectionCalculate(prismOption);
                    var diffArray = prismSectionCaculate.calculateDiff();
                    if (diffArray[0] !== null) {
                        var mile = yield _this._getMileSum(targetNow);
                        var line = _this.surveyFitLine.getLineAtMile(targetNow.mileage + mile);
                        var deltaE = diffArray[0] / (line.distance) * Math.abs(line.endPoint.n - line.startPoint.n) * Math.sign(coorDiff.deltaE);
                        var deltaN = diffArray[0] / (line.distance) * Math.abs(line.endPoint.e - line.startPoint.e) * Math.sign(coorDiff.deltaN);
                        var deltaH = diffArray[1];
                        console.log(chalk.gray('旧的E方向偏差:') + chalk.green(sectionCenter.e - targetOriginal.e));
                        console.log(chalk.gray('旧的N方向偏差:') + chalk.green(sectionCenter.n - targetOriginal.n));
                        console.log(chalk.gray('旧的H方向偏差:') + chalk.green(sectionCenter.h - targetOriginal.h));
                        console.log(chalk.gray('新的E方向偏差:') + chalk.green(deltaE));
                        console.log(chalk.gray('新的N方向偏差:') + chalk.green(deltaN));
                        console.log(chalk.gray('新的H方向偏差:') + chalk.green(deltaH));
                        yield models.CoorDiff.update({
                            deltaE: deltaE,
                            deltaN: deltaN,
                            deltaH: deltaH
                        }, {
                                where: {
                                    prjId: _this.prjId,
                                    name: targetNow.name
                                }
                            });
                    }
                }
                //完成棱镜计算旋转角
                //------------
                //开始倾角计计算旋转
                continue;
                var angleDevice = _this.angleDeviceList.find(d=> { return d.section === targetNow.name });
                if (!angleDevice) continue;
                var angleOrigin = yield models.AngleDeviceResult.findOne({
                    where: {
                        configId: angleDevice.configId,
                        deviceId: angleDevice.deviceId
                    },
                    order: [['Date', 'ASC']]
                });
                var angleNow = yield models.AngleDeviceResult.findOne({
                    where: {
                        configId: angleDevice.configId,
                        deviceId: angleDevice.deviceId
                    },
                    order: [['Date', 'DESC']]
                });
                if (sectionCenter && targetOriginal && angleOrigin && angleNow && angleOrigin.x !== null && angleNow.x !== null) {
                    var angleOption = {
                        sectionCenter: sectionCenter,
                        targetOriginal: targetOriginal,
                        angleOriginal: angleOrigin.x,
                        angleNow: angleNow.x
                    };
                    var angleCoorDiff = yield models.AngleCoorDiff.findOne({
                        where: {
                            prjId: _this.prjId,
                            name: targetNow.name
                        }
                    });
                    var angleSectionCaculate = new AngleSectionCalculate(angleOption);
                    var angleDiffArray = angleSectionCaculate.calculateDiff();
                    if (angleDiffArray[0] !== null) {
                        var angleDeltaE = angleDiffArray[0] / (line.distance) * Math.abs(line.endPoint.n - line.startPoint.n) * Math.sign(angleCoorDiff.deltaE);
                        var angleDeltaN = angleDiffArray[0] / (line.distance) * Math.abs(line.endPoint.e - line.startPoint.e) * Math.sign(angleCoorDiff.deltaN);
                        var angleDeltaH = angleDiffArray[1];
                        yield models.AngleCoorDiff.update({
                            deltaE: angleDeltaE,
                            deltaN: angleDeltaN,
                            deltaH: angleDeltaH
                        }, {
                                where: {
                                    prjId: _this.prjId,
                                    name: targetNow.name
                                }
                            });
                    }
                }
            }
        }).catch(function (err) {
            console.log(err.stack);
        });
    }
    
    /** 
     * 常规测量的数据处理
     */
    _surveyControlProcess(turnData, no) {
        var _this = this;
        return co(function* () {
            var pts = turnData.surveyResultList
                .filter(function (item) {
                    return item.pass;
                })
                .map(function (pt) {
                    return Object.assign(pt, {
                        date: pt.time1,
                        no: no,
                        stationId: _this.option.stationConfig.id
                    });
                });//不pass的就不要了
            var pb = pts.find(pt=> {
                return pt.name === 'pb';
            });
            var pf = pts.find(pt=> {
                return pt.name === 'pf';
            });
            var ph = pts.find(pt=> {
                return pt.name === 'ph';
            });
            var savePts = pts.map(function (pt) {
                return {
                    name: pt.name,
                    date: pt.time1,
                    no: no,
                    e: pt.e,
                    n: pt.n,
                    h: pt.h,
                    stationId: _this.option.stationConfig.id
                }
            });
            console.table(savePts);
            yield models.TargetPrismResult.bulkCreate(savePts);//保存的到数据库
            if (pb && ph && pf) {//必须都要测量到
                var toBeUpdatedPrism = {
                    pb: pb,
                    ph: ph,
                    pf: pf
                };
                for (var key in toBeUpdatedPrism) {
                    //先把棱镜坐标update到学习表中去
                    yield models.TargetPrismConfig.update({
                        e: toBeUpdatedPrism[key].e,
                        n: toBeUpdatedPrism[key].n,
                        h: toBeUpdatedPrism[key].h,
                    }, {
                            where: {
                                stationId: _this.option.stationConfig.id,
                                name: key.toString()
                            }
                        });
                }

                var pbMileSum = yield _this._getMileSum(pb);
                var pbCoor = _this.surveyFitLine.getCoorAtMile(pb.mileage + pbMileSum);
                console.log(chalk.gray('pb的当前里程是:') + chalk.green(pb.mileage + pbMileSum));
                var pbDiff = yield models.CoorDiff.findOne({
                    where: {
                        prjId: _this.prjId,
                        name: 'pb'
                    }
                });
                pbCoor.e = pbCoor.e - pbDiff.deltaE; pbCoor.n = pbCoor.n - pbDiff.deltaN; pbCoor.h = pbCoor.h - pbDiff.deltaH;//从中心反算到管壁棱镜坐标
                console.log(chalk.yellow('pb0中心的坐标为:'));
                console.table([pbCoor]);
                //st处的里程累加就用pb点时间的
                var stCoor = _this.surveyFitLine.getCoorAtMile(_this.stationConfig.mileage + pbMileSum);
                console.log(chalk.gray('st的当前里程是:') + chalk.green(_this.stationConfig.mileage + pbMileSum));
                var stDiff = yield models.CoorDiff.findOne({
                    where: {
                        prjId: _this.prjId,
                        name: 'st'
                    }
                });
                stCoor.e = stCoor.e - stDiff.deltaE; stCoor.n = stCoor.n - stDiff.deltaN; stCoor.h = stCoor.h - stDiff.deltaH;//从中心反算到管壁全站仪坐标
                console.log(chalk.yellow('st0中心的坐标为:'));
                console.table([stCoor]);
                var pfAngleDiff = pf.hz - pb.hz;
                var phAngleDiff = ph.hz - pb.hz;
                var vector = new Tps.SurveyVector(stCoor, pbCoor);
                var tps = new Tps.TPS(stCoor.e, stCoor.n, stCoor.h);
                var pfCoor = tps.convertToXYZ(vector.horizontalAngle + pfAngleDiff, pf.hv, pf.slope);//得到pf在实际坐标系下的坐标
                var pfDiff = yield models.CoorDiff.findOne({
                    where: {
                        prjId: _this.prjId,
                        name: 'pf'
                    }
                });
                pfCoor.e = pfCoor.e + pfDiff.deltaE; pfCoor.n = pfCoor.n + pfDiff.deltaN; pfCoor.h = pfCoor.h + pfDiff.deltaH;//从pf位置计算到pf所在的管壁中心
                var pfMileSum = yield _this._getMileSum(pf);
                var phCoor = tps.convertToXYZ(vector.horizontalAngle + phAngleDiff, ph.hv, ph.slope);//得到ph在实际坐标系下的坐标
                var phDiff = yield models.CoorDiff.findOne({
                    where: {
                        prjId: _this.prjId,
                        name: 'ph'
                    }
                });
                phCoor.e = phCoor.e + phDiff.deltaE; phCoor.n = phCoor.n + phDiff.deltaN; phCoor.h = phCoor.h + phDiff.deltaH;//从ph位置计算到ph所在的管壁中心
                var phMileSum = yield _this._getMileSum(ph);
                var designCoor = _this.surveyFitLine.getDesignCoorAtMile(ph.mileage + phMileSum);
                console.log(chalk.gray('ph的当前里程是:') + chalk.green(ph.mileage + phMileSum));
                //获取设计坐标系下该里程所在的坐标
                var phCoorVsDesign = {
                    e: phCoor.e - designCoor.e,
                    n: phCoor.n - designCoor.n,
                    h: phCoor.h - designCoor.h,
                };
                console.log('实测与设计的里程差为:');
                console.table([phCoorVsDesign]);
                fs.appendFile(path.join(__dirname, './../ph_Diff.txt'), `${moment(ph.date).format('YYYY-MM-DD HH:mm:ss') },${phCoorVsDesign.e},${phCoorVsDesign.n},${phCoorVsDesign.h}\r\n`);//存到文本文件里去
                _this.emit('phdiffcomplete', phCoorVsDesign);//发布事件ph工具头与设计中心线的坐标对比
                //然后储存到SurveyCenter表中去
                var newPf = {
                    e: pfCoor.e,
                    n: pfCoor.n,
                    h: pfCoor.h,
                    mileage: pfMileSum + pf.mileage,
                    prjId: _this.prjId
                };
                console.log('实测的pf处中心点为:');
                console.table([newPf]);
                fs.appendFile(path.join(__dirname, './../pf0_coor.txt'), `${moment().format('YYYY-MM-DD HH:mm:ss') },${newPf.e},${newPf.n},${newPf.h},${newPf.mileage},${newPf.prjId}\r\n`);
                _this.surveyFitLine.addSurveyPoint(newPf);
            }
        }).catch(function (err) {
            console.log(err.stack);
        });
    }
    
    /** 
     * 开始一组测量
     */
    _survey() {
        var _this = this;
        return co(function* () {
            if (!_this.enabled) {
                console.log(chalk.blue('拟合并储存测量点数据,SurveyCenter'));
                yield _this.surveyFitLine.processPointCache();
                console.log(chalk.green('全站仪测量已经停止'));
                yield _this.closePort();
                return;
            }
            yield q.delay(1000);
            if (_this.firstSurveyInPipe) {//第一次测该顶管的时候,进入辅助测量
                yield _this.auxiliarySurvey();
                yield q.delay(2000);
            }
            yield _this.controlSurvey();
            yield _this._survey();
        }).catch(function (err) {
            console.log(err.stack);
        });
    }
}

module.exports = TpsHelper;